//
//  Timer.hxx
//  Simulation
//
//  Created by Christopher Kemsley on 2/24/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#ifndef Simulation_Timer_hxx
#define Simulation_Timer_hxx

#include "Timer.hpp"
#include "Log.hpp"

using namespace Sim ;






Timer :: Timer	( Interval const & inInterval , Invocation * inInvocation )
:	mIsPaused	( false )
,	mFireDate	( inInterval )
,	mInterval	( inInterval )
,	mInvocation	( inInvocation )
	{
	if ( mInvocation == 0 )
		throw Exception ( "Timer" , "Constructed with nil invocation" , __FILE__,__LINE__ ) ;
	
	if ( inInterval.isNegative() )
		ThrowException ( "Timer" , "Timer created with negative interval" , __FILE__,__LINE__ ) ;
	
	mInvocation -> retain () ;
	
	mFireDate += System::shared().currentTime() ;
	performRegistration() ;
	}




Timer :: ~Timer ()
	{
	performUnregistration() ;
	
	mInvocation -> release () ;
	}




bool	Timer :: isPaused () const
	{
	return mIsPaused ;
	}



void	Timer :: setIsPaused ( bool paused )
	{
	paused &= 1 ; // make sure it's always '1' or '0'
	if ( paused != mIsPaused )
		{
		mIsPaused = paused ;
		if ( paused )
			{
			// Store it
			mInterval	=	mFireDate ;
			mInterval	-=	System::shared().currentTime() ;
			
			mFireDate	=	Interval::distantFuture ;
			
			Log::states("Timer") << this << "Pausing with " << mInterval << " remaining" ;
			
			// Remove our source
			performUnregistration() ;
			}
		else
			{
			// Add the current time to the remaining time
			Interval const & now	=	System::shared().currentTime() ;
			mFireDate	+=	now ;
			
			Log::states("Timer") << this << "Resuming @ " << mFireDate ;
			
			// Add our source
			performRegistration() ;
			}
		}
	}

void	Timer :: restart	( Interval const & newInterval )
	{
	Interval const & now	=	System::shared().currentTime() ;
	mFireDate = now + newInterval ;
	if ( mIsPaused )
		{
		mIsPaused = 0 ;
		performRegistration() ;
		}
	}



void	Timer :: fire ()
	{
	Interval const & now	=	System::shared().currentTime() ;
	if ( mFireDate <= now )
		{
		mFireDate = Interval::distantFuture ;
		mInvocation -> invoke () ;
		}
	}
Interval const	Timer :: fireDate ()
	{
	if ( mIsPaused )
		return Interval::distantFuture ;
	return mFireDate ;
	}



#endif
